package mt.comm;
import mt.Order;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.LinkedBlockingQueue;

public class ClientCommClass implements ClientComm{
	private Socket socket;
	private String clientNickname;
	private boolean clientConnected = false;
	private ObjectInputStream ois;
	private ObjectOutputStream oos;
	private LinkedBlockingQueue<ClientSideMessage> lbQueue  = new LinkedBlockingQueue<ClientSideMessage>();
	private String host;

	public ClientCommClass(String host, String nickname) {
		this.host = host;
		this.clientNickname = nickname;
	}

	@Override
	public void connect(String host, String nickname) throws UnknownHostException, IOException {

		// Create a socket for the connection, start the input and output streams
		clientNickname = nickname;    	
		InetAddress address = InetAddress.getByName(host);

		try {
			socket = new Socket(address, ServerCommClass.PORT);
			System.out.println(nickname + " --> CONNECTED TO SERVER");

			oos = new ObjectOutputStream(socket.getOutputStream());
			ServerSideMessage clientMsg = new ServerSideMessageClass(mt.comm.ServerSideMessage.Type.CONNECTED, null, clientNickname);
			oos.writeObject(clientMsg);
			oos.flush();
			clientConnected = true;

			ois = new ObjectInputStream(socket.getInputStream());
			new getServerInput(ois).start();
		} catch (Exception e2) {
			System.out.println(nickname + " --> Socket could not be created");
			//e2.printStackTrace();
		}        
	}

	class getServerInput extends Thread {
		private ObjectInputStream ois;

		public getServerInput(ObjectInputStream ois) {
			this.ois = ois;
		}

		@Override
		public void run() {
			while (clientConnected) {
				try {
					ClientSideMessage msg;
					msg = (ClientSideMessage) ois.readObject();
					System.out.println(clientNickname + " --> Message received");
					lbQueue.put(msg);
				} catch (ClassNotFoundException e) {
					break;
				} catch (IOException e) {
					break;
				} catch (InterruptedException e) {
					break;
				}
			}
		}
	}

	@Override
	public boolean isConnected() {
		// Returns a boolean, whether the client socket is connected
		if (socket == null){
			return false;
		}

		return socket.isConnected();
	}

	@Override
	public void disconnect() {
		if (this.isConnected()){
			// Send one last message to the server informing that the client will disconnect
			// Disconnects the client socket
			ServerSideMessage serverMsg = new ServerSideMessageClass (mt.comm.ServerSideMessage.Type.DISCONNECTED, null, clientNickname);
			try {
				oos.writeObject(serverMsg);
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				socket.close();
				System.out.println(clientNickname + " --> DISCONNECTED");
				clientConnected = false;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return;
	}

	@Override
	public ClientSideMessage getNextMessage() {

		// Take if there are any, pending messages from clients
		try {
			ClientSideMessage serverMsg = lbQueue.take();
			return serverMsg;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public boolean hasNextMessage() {

		if (lbQueue == null){
			return false;
		}
		// Check if there are any pending messages from clients
		return !(lbQueue.isEmpty());
	}

	@Override
	public void sendOrder(Order order)  {
		//System.out.println("--> Client is sending the order");
		// Compose the message to send and write it to the output stream
		Order newOrder = order;
		ServerSideMessage orderMsg = new ServerSideMessageClass(mt.comm.ServerSideMessage.Type.NEW_ORDER, newOrder, clientNickname);
		if (orderMsg != null){
			try {
				//System.out.println("--> Message composed, sending...");
				oos.writeObject(orderMsg);
			} catch (IOException e) {
				System.out.println("--> Could not send message");
				e.printStackTrace();
			}
		}    	
	}
}
